﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Data;
using Extensil.Common.CategoryHandler.Discovery;
using System.Reflection;

namespace Extensil.Common.CategoryHandler
{
    public class ConfigModifier : IDisposable
    {
        Configuration config;
        ConfigurationSection categorySection;
        PluginHandlers categoryHandlers;
        DiscoverySection dSection;
        PluginHandlers probeHandlers;
        public ConfigModifier()
        {
            // config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            config = ConfigurationManager.OpenMappedExeConfiguration(
                        new ExeConfigurationFileMap()
                        {
                            ExeConfigFilename = Assembly.GetEntryAssembly().Location + ".config"
                        }, ConfigurationUserLevel.None);

            categorySection = config.GetSection("CategorySection");
            if(categorySection == null)
                throw new CategorySectionNotDefined();
            categoryHandlers = ((CategorySection)categorySection).CategoryHandlers;
            dSection = ((CategorySection)categorySection).DiscoverySection;
            probeHandlers = ((CategorySection)categorySection).ProbeHandlers;
        }
        #region Category Handler
        public bool ToggleFirstTime()
        {
            ((CategorySection)categorySection).IsFirstTime = !((CategorySection)categorySection).IsFirstTime;
            return ((CategorySection)categorySection).IsFirstTime;
        }
        public void AddCategoryHandler(PluginHandler cat)
        {
            categoryHandlers.Add(cat);
        }
        public void RemoveCategoryHandler(PluginHandler cat)
        {
            categoryHandlers.Remove(cat);
        }

        public void EditCategoryHandler(int index, PluginHandler cat)
        {
            categoryHandlers[index] = cat;
        }
        public void EditCategoryHandler(string key, PluginHandler cat)
        {
            categoryHandlers[categoryHandlers.IndexOf(categoryHandlers[key])] = cat;
        }

        public void MoveCategoryHandler(string catName, MoveDirection dir)
        {
            PluginHandler exchanger;
            switch(dir)
            {
                case MoveDirection.Up:
                    exchanger = PreviousCategoryHandlerOf(categoryHandlers[catName]);
                    break;
                case MoveDirection.Down:
                default:
                    exchanger = NextCategoryHandlerOf(categoryHandlers[catName]);
                    break;
            }
            if(exchanger == null)
                return;
            int order = categoryHandlers[catName].Order;
            categoryHandlers[catName].Order = exchanger.Order;
            exchanger.Order = order;
        }
        PluginHandler PreviousCategoryHandlerOf(PluginHandler cat)
        {
            string catName = String.Empty;
            DataTable sCat = SortedCategoriesDataSet;
            for(int i = 0; i < sCat.Rows.Count; i++)
            {
                DataRow dr = sCat.Rows[i];
                if((int)dr["Order"] == cat.Order)
                {
                    if(i != 0)
                        catName = sCat.Rows[i - 1]["Name"].ToString();
                    break;
                }
            }
            return categoryHandlers[catName];
        }
        PluginHandler NextCategoryHandlerOf(PluginHandler cat)
        {
            string catName = String.Empty;
            DataTable sCat = SortedCategoriesDataSet;
            for(int i = 0; i < sCat.Rows.Count; i++)
            {
                DataRow dr = sCat.Rows[i];
                if((int)dr["Order"] == cat.Order)
                {
                    if(sCat.Rows.Count > i + 1)
                        catName = sCat.Rows[i + 1]["Name"].ToString();
                    break;
                }
            }
            return categoryHandlers[catName];
        }
        public static DataTable SortedCategoriesDataSet
        {
            get
            {
                DataTable retValue = new DataTable();
                retValue.Columns.Add("Name");
                retValue.Columns.Add("Path");
                retValue.Columns.Add("Order", typeof(int));
                retValue.Columns.Add("Version");
                retValue.Columns.Add("AutoStart");
                retValue.Columns.Add("HotKey");
                retValue.Columns.Add("Visibility");
                
                PluginHandlers catList = CategorySection.GetConfig().CategoryHandlers;
                int maxOrder = 0;
                foreach(Extensil.Common.CategoryHandler.PluginHandler cat in catList)
                {
                    if(cat.Order > maxOrder)
                        maxOrder = cat.Order;
                    retValue.Rows.Add(cat.Name, cat.Path, cat.Order, cat.Version, cat.AutoStart, cat.HotKey, !cat.Hidden);
                }
                retValue = TuneCategorySet(retValue, maxOrder);
                retValue.DefaultView.Sort = "Order asc";
                retValue = retValue.DefaultView.ToTable();
                return retValue;
            }
        }
        static DataTable TuneCategorySet(DataTable dt, int maxOrder)
        {
            foreach(DataRow dr in dt.Rows)
            {
                if((int)dr["Order"] <= 0)
                {
                    maxOrder = maxOrder + 1;
                    dr["Order"] = maxOrder;
                    using(ConfigModifier cm = new ConfigModifier())
                    {
                        cm.SetCategoryOrder(dr["Name"].ToString(), maxOrder);
                    }
                }
            }
            return dt;
        }
        public void SetCategoryOrder(string catName, int order)
        {
            categoryHandlers[catName].Order = order;
        }

        public bool ToggleVisibilityOfCategory(string catName)
        {
            PluginHandler cat = categoryHandlers[catName];
            if(cat != null)
                cat.Hidden = !cat.Hidden;
            return !cat.Hidden;
        }
        public bool ToggleAutoStartOfCategory(string catName)
        {
            PluginHandler cat = categoryHandlers[catName];
            if(cat != null)
                cat.AutoStart = !cat.AutoStart;
            return cat.AutoStart;
        }
        public void SetHotkeyOfCategory(string catName, string hotKey)
        {
            PluginHandler cat = categoryHandlers[catName];
            if(cat != null)
                cat.HotKey = hotKey;
        }
        public void AddUpdateApplicationSettingParameter(string catName, string key, string value)
        {
            PluginHandler cat = categoryHandlers[catName];
            if(cat != null)
            {
                if(cat.CategorySettings[key] == null)
                    cat.CategorySettings.Add(key, value);
                else
                    cat.CategorySettings[key].Value = value;
            }
        }
        #endregion

        #region Discovery
        public DateTime LastUpdate
        {
            get
            {
                return dSection.LastUpdate;
            }
            set
            {
                dSection.LastUpdate = value;
            }
        }
        public bool AllowDiscovery
        {
            get
            {
                return dSection.IsActive;
            }
            set
            {
                dSection.IsActive = value;
            }
        }
        public bool AllowAutoUpgrade
        {
            get
            {
                return dSection.IsAutoUpdateEnabled;
            }
            set
            {
                dSection.IsAutoUpdateEnabled = value;
            }
        }
        public int ProbeInterval
        {
            get
            {
                return dSection.ProbeInterval;
            }
            set
            {
                dSection.ProbeInterval = value;
            }
        }
        #endregion


        #region Probe Handler
        public void AddProbeHandler(PluginHandler hnd)
        {
            probeHandlers.Add(hnd);
        }
        public void RemoveProbeHandler(PluginHandler hnd)
        {
            probeHandlers.Remove(hnd);
        }

        public void EditProbeHandler(int index, PluginHandler hnd)
        {
            probeHandlers[index] = hnd;
        }
        public void EditProbeHandler(string key, PluginHandler hnd)
        {
            probeHandlers[probeHandlers.IndexOf(probeHandlers[key])] = hnd;
        }

        #endregion

        #region Probe
        public bool ToggleProbe(string probeName)
        {
            Probe prb = dSection[probeName];
            if(prb != null)
                prb.IsActive = !prb.IsActive;
            return prb.IsActive;
        }
        public void AddProbe(Probe prb)
        {
            dSection.Add(prb);
        }
        public void DeleteProbe(string probeName)
        {
            dSection.Remove(dSection[probeName]);
        }
        public void EditProbe(string probeName, Probe prb)
        {
            dSection[dSection.IndexOf(dSection[probeName])] = prb;
        }
        #endregion
        void IDisposable.Dispose()
        {
            categorySection.SectionInformation.ForceSave = true;
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("CategorySection");
        }
    }
    
    public enum MoveDirection
    {
        Up,
        Down
    }
}
